/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.core.netvalidator;

import java.util.ArrayList;
import java.util.List;

import org.jdpf.core.kernel.elements.ITransition;
import org.jdpf.core.kernel.elements.InputArc;
import org.jdpf.core.kernel.elements.Net;
import org.jdpf.core.kernel.elements.OutputArc;
import org.jdpf.core.kernel.elements.Place;
import org.jdpf.core.kernel.exceptions.CoreException;
import org.jdpf.core.kernel.exceptions.CoreExceptionsEnum;
import org.jdpf.core.kernel.logging.ILogger;
import org.jdpf.core.kernel.logging.LoggerFactory;
import org.jdpf.core.kernel.plugins.IPluginsFrameworkConstants;
import org.jdpf.core.plugins.parameters.ManifestParameterValidator;

/**
 * This performs the static net validations. It means that the component is not
 * going to be fired. It is pure topological and manifests checking.
 * 
 * @author Paolo Ciccarese, Cristiana Larizza, Bruno Farina, Paolo Mauri
 */
public class StaticNetValidator {

	private static final ILogger logger = LoggerFactory.getDefault()
			.getLogger();

	private static final String NO_GENERATOR = "Missing generator after start place in net";

	private static final String NO_SERIALIZER = "Missing serializer before end place in net";

	public void validateNetStatically(Net net) throws CoreException {
		checkStartPlaces(net);
		if (net.isValid())
			checkEndPlaces(net);
		if (net.isValid())
			checkAllManifests(net);
	}

	private void checkAllManifests(Net net) throws CoreException {
		List<String> pluginIds = new ArrayList<String>(5);
		for (ITransition t : net.getAllTransitions()) {
			String pluginId = null;
			try {
				pluginId = (String) t.getClass().getMethod("getPluginId", null)
						.invoke(t, null);
			} catch (Exception e) {
				logger.error(this, net.getName(), e.getMessage());
			}
			if (!pluginIds.contains(pluginId)) {
				pluginIds.add(pluginId);

				ManifestParameterValidator mpv = new ManifestParameterValidator(
						true, pluginId);
				mpv.checkParameter();

			}
		}
	}

	private void checkStartPlaces(Net net) throws CoreException {
		List<Place> startPlaces = net.getStartPlaces();
		boolean flag = true;
		for (Place place : startPlaces) {
			for (InputArc arc : place.getOutputArcs()) {
				ITransition tr = arc.getTransition();
				String category = null;
				try {
					category = (String) tr.getClass().getMethod("getCategory",
							null).invoke(tr, null);
				} catch (Exception e) {
					net.setValid(false);
					logger.error(this, net.getName(), e.getMessage());
				}
				flag = flag
						&& (category
								.equalsIgnoreCase(IPluginsFrameworkConstants.GENERATOR));
			}
		}
		if (!flag) {
			logger.error(this, StaticNetValidator.NO_GENERATOR + " "
					+ net.getName());
			net.setValid(flag);
			throw new CoreException(CoreExceptionsEnum.BadWiring,
					StaticNetValidator.NO_GENERATOR + net.getName());
		}
	}

	private void checkEndPlaces(Net net) throws CoreException {
		List<Place> endPlaces = net.getEndPlaces();
		boolean flag = true;
		for (Place place : endPlaces) {
			for (OutputArc arc : place.getInputArcs()) {
				ITransition tr = arc.getTransition();
				String category = null;
				try {
					category = (String) tr.getClass().getMethod("getCategory",
							null).invoke(tr, null);
				} catch (Exception e) {
					net.setValid(false);
					logger.error(this, net.getName(), e.getMessage());
				}
				flag = flag
						&& (category
								.equalsIgnoreCase(IPluginsFrameworkConstants.SERIALIZER) || category
								.equalsIgnoreCase(IPluginsFrameworkConstants.INSPECTOR));
			}
		}
		if (!flag) {
			logger
					.error(StaticNetValidator.NO_SERIALIZER + " "
							+ net.getName());
			net.setValid(flag);
			throw new CoreException(CoreExceptionsEnum.BadWiring,
					StaticNetValidator.NO_SERIALIZER + net.getName());
		}
	}

}
